/*
 * Wazuh Send report test
 * Copyright (C) 2015, Wazuh Inc.
 * March 9, 2024.
 *
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General Public
 * License (version 2) as published by the FSF - Free Software
 * Foundation.
 */

#include "clearSendReport_test.hpp"
#include "../../../../shared_modules/utils/flatbuffers/include/rsync_generated.h"
#include "../../../../shared_modules/utils/flatbuffers/include/rsync_schema.h"
#include "../scanOrchestrator/clearSendReport.hpp"
#include "MockOsDataCache.hpp"
#include "MockReportDispatcher.hpp"
#include "TrampolineOsDataCache.hpp"
#include "TrampolineRemediationDataCache.hpp"
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
#include "socketClient.hpp"
#include "socketServer.hpp"

using ::testing::_;

const size_t MAX_RETRIES {10};
auto constexpr TEST_REPORTS_QUEUE_PATH {"queue/vd/reports"};
auto constexpr TEST_REPORTS_BULK_SIZE {1};

namespace NSClearSendReportTest
{

    const std::string INTEGRITY_CLEAR_MSG_PACKAGES {
        R"(
            {
                "agent_info": {
                    "agent_id": "001",
                    "agent_ip": "192.168.33.20",
                    "agent_name": "focal"
                },
                "data_type": "integrity_clear",
                "data": {
                    "attributes_type": "syscollector_packages",
                    "id": 1700236640
                }
            }
        )"};

    const std::string INTEGRITY_CLEAR_MSG_OS {
        R"(
            {
                "agent_info": {
                    "agent_id": "001",
                    "agent_ip": "192.168.33.20",
                    "agent_name": "focal"
                },
                "data_type": "integrity_clear",
                "data": {
                    "attributes_type": "syscollector_osinfo",
                    "id": 1700236640
                }
            }
        )"};

    const std::string INTEGRITY_CLEAR_MSG_UNEXPECTED {
        R"(
            {
                "agent_info": {
                    "agent_id": "001",
                    "agent_ip": "192.168.33.20",
                    "agent_name": "focal"
                },
                "data_type": "integrity_clear",
                "data": {
                    "attributes_type": "syscollector_unexpected",
                    "id": 1700236640
                }
            }
        )"};

    // Helpers

    const Os osData {.hostName = "osdata_hostname",
                     .architecture = "osdata_architecture",
                     .name = "osdata_name",
                     .codeName = "osdata_codeName",
                     .majorVersion = "osdata_majorVersion",
                     .minorVersion = "osdata_minorVersion",
                     .patch = "osdata_patch",
                     .build = "osdata_build",
                     .platform = "osdata_platform",
                     .version = "osdata_version",
                     .release = "osdata_release",
                     .displayVersion = "osdata_displayVersion",
                     .sysName = "osdata_sysName",
                     .kernelVersion = "osdata_kernelVersion",
                     .kernelRelease = "osdata_kernelRelease"};

    void expectOsData()
    {

        spOsDataCacheMock = std::make_shared<MockOsDataCache>();
        EXPECT_CALL(*spOsDataCacheMock, getOsData(_, _))
            .WillOnce(testing::Invoke(
                [](const std::string&, Os& osDataResult)
                {
                    osDataResult = osData;
                    return true;
                }));
    }
} // namespace NSClearSendReportTest

using namespace NSClearSendReportTest;

TEST_F(ClearSendReportTest, SendFormattedMsgPackages)
{
    // Mock report dispatcher.
    std::shared_ptr<MockReportDispatcher> reportDispatcher = std::make_shared<MockReportDispatcher>();
    // Send report instance.
    TClearSendReport<TScanContext<TrampolineOsDataCache, GlobalData, TrampolineRemediationDataCache>,
                     MockReportDispatcher>
        sendReport(reportDispatcher);

    spRemediationDataCacheMock = std::make_shared<MockRemediationDataCache>();
    EXPECT_CALL(*spRemediationDataCacheMock, getRemediationData(_)).WillRepeatedly(testing::Return(Remediation {}));

    // Mock scanContext.
    flatbuffers::Parser parser;
    ASSERT_TRUE(parser.Parse(rsync_SCHEMA));
    ASSERT_TRUE(parser.Parse(INTEGRITY_CLEAR_MSG_PACKAGES.c_str()));
    uint8_t* buffer = parser.builder_.GetBufferPointer();
    std::variant<const SyscollectorDeltas::Delta*, const Synchronization::SyncMsg*, const nlohmann::json*>
        syscollectorSync = Synchronization::GetSyncMsg(reinterpret_cast<const char*>(buffer));
    auto scanContext =
        std::make_shared<TScanContext<TrampolineOsDataCache, GlobalData, TrampolineRemediationDataCache>>(
            syscollectorSync);
    scanContext->m_alerts["clean"] = nlohmann::json::object();

    EXPECT_CALL(*reportDispatcher, push(_)).Times(1);

    // Send report.
    EXPECT_NO_THROW(sendReport.handleRequest(scanContext));
}

TEST_F(ClearSendReportTest, SendFormattedMsgOsInfo)
{
    // Mock report dispatcher.
    std::shared_ptr<MockReportDispatcher> reportDispatcher = std::make_shared<MockReportDispatcher>();
    // Send report instance.
    TClearSendReport<TScanContext<TrampolineOsDataCache, GlobalData, TrampolineRemediationDataCache>,
                     MockReportDispatcher>
        sendReport(reportDispatcher);

    spRemediationDataCacheMock = std::make_shared<MockRemediationDataCache>();
    EXPECT_CALL(*spRemediationDataCacheMock, getRemediationData(_)).WillRepeatedly(testing::Return(Remediation {}));

    // Mock scanContext.
    flatbuffers::Parser parser;
    ASSERT_TRUE(parser.Parse(rsync_SCHEMA));
    ASSERT_TRUE(parser.Parse(INTEGRITY_CLEAR_MSG_OS.c_str()));
    uint8_t* buffer = parser.builder_.GetBufferPointer();
    std::variant<const SyscollectorDeltas::Delta*, const Synchronization::SyncMsg*, const nlohmann::json*>
        syscollectorSync = Synchronization::GetSyncMsg(reinterpret_cast<const char*>(buffer));
    auto scanContext =
        std::make_shared<TScanContext<TrampolineOsDataCache, GlobalData, TrampolineRemediationDataCache>>(
            syscollectorSync);
    scanContext->m_alerts["clean"] = nlohmann::json::object();

    EXPECT_CALL(*reportDispatcher, push(_)).Times(1);

    // Send report.
    EXPECT_NO_THROW(sendReport.handleRequest(scanContext));
}

TEST_F(ClearSendReportTest, SendFormattedMsgUnexpected)
{
    // Mock report dispatcher.
    std::shared_ptr<MockReportDispatcher> reportDispatcher = std::make_shared<MockReportDispatcher>();
    // Send report instance.
    TClearSendReport<TScanContext<TrampolineOsDataCache, GlobalData, TrampolineRemediationDataCache>,
                     MockReportDispatcher>
        sendReport(reportDispatcher);

    spRemediationDataCacheMock = std::make_shared<MockRemediationDataCache>();
    EXPECT_CALL(*spRemediationDataCacheMock, getRemediationData(_)).WillRepeatedly(testing::Return(Remediation {}));

    // Mock scanContext.
    flatbuffers::Parser parser;
    ASSERT_TRUE(parser.Parse(rsync_SCHEMA));
    ASSERT_TRUE(parser.Parse(INTEGRITY_CLEAR_MSG_UNEXPECTED.c_str()));
    uint8_t* buffer = parser.builder_.GetBufferPointer();
    std::variant<const SyscollectorDeltas::Delta*, const Synchronization::SyncMsg*, const nlohmann::json*>
        syscollectorSync = Synchronization::GetSyncMsg(reinterpret_cast<const char*>(buffer));
    auto scanContext =
        std::make_shared<TScanContext<TrampolineOsDataCache, GlobalData, TrampolineRemediationDataCache>>(
            syscollectorSync);
    scanContext->m_alerts["clean"] = nlohmann::json::object();

    EXPECT_CALL(*reportDispatcher, push(_)).Times(1);

    // Send report.
    EXPECT_NO_THROW(sendReport.handleRequest(scanContext));
}

TEST_F(ClearSendReportTest, SendFormattedMsgThrow)
{
    // Mock report dispatcher.
    std::shared_ptr<MockReportDispatcher> reportDispatcher = std::make_shared<MockReportDispatcher>();
    // Send report instance.
    TClearSendReport<TScanContext<TrampolineOsDataCache, GlobalData, TrampolineRemediationDataCache>,
                     MockReportDispatcher>
        sendReport(reportDispatcher);

    spRemediationDataCacheMock = std::make_shared<MockRemediationDataCache>();
    EXPECT_CALL(*spRemediationDataCacheMock, getRemediationData(_)).WillRepeatedly(testing::Return(Remediation {}));

    // Mock scanContext.
    flatbuffers::Parser parser;
    ASSERT_TRUE(parser.Parse(rsync_SCHEMA));
    ASSERT_TRUE(parser.Parse(INTEGRITY_CLEAR_MSG_UNEXPECTED.c_str()));
    uint8_t* buffer = parser.builder_.GetBufferPointer();
    std::variant<const SyscollectorDeltas::Delta*, const Synchronization::SyncMsg*, const nlohmann::json*>
        syscollectorSync = Synchronization::GetSyncMsg(reinterpret_cast<const char*>(buffer));
    auto scanContext =
        std::make_shared<TScanContext<TrampolineOsDataCache, GlobalData, TrampolineRemediationDataCache>>(
            syscollectorSync);
    scanContext->m_alerts["clean"] = nlohmann::json::object();

    // Simulate an exception in push method.
    EXPECT_CALL(*reportDispatcher, push(_)).WillOnce(testing::Throw(std::runtime_error("Error")));

    // Send report.
    EXPECT_NO_THROW(sendReport.handleRequest(scanContext));
}
